home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
language
/
pcl_src.zoo
/
lap.txt
< prev
next >
Wrap
Text File
|
1990-01-25
|
27KB
|
656 lines
-*- Mode: Text -*-
Copyright (c) 1985, 1986, 1987, 1988, 1989 Xerox Corporation.
All rights reserved.
Use and copying of this document is permitted. Any distribution of this
document must comply with all applicable United States export control
laws.
Last updated: 6/3/89 by Gregor
10/26/89 by Gregor -- added :RETURN, removed :ISHIFT
This file contains documentation of the PCL abstract LAP code. Any port
of PCL is required to implement the abstract LAP code interface. There
is a portable, relatively good performance implementation in the file
lap.lisp, port-specific implementations are in that file as well.
The PCL abstract LAP code mechanism exists to provide PCL with a way to
create high-performance method lookup functions. Using this mechanism,
PCL can produce "LAP closures" which do the method lookup. By allowing
PCL to specify these closures using abstract LAP code rather that Lisp
code we hope to achieve the following:
* Better runtime performance. By using abstract LAP code, we
will get better machine instruction sequences than we would
from compiling Lisp code.
* Better load and update time performance. Because it should
be possible to "assemble" the LAP code more quickly than
compiling Lisp code, PCL will spend less time building the
method lookup code.
* Ability to use PCL without a compiler. The LAP assembler will
still be required but this should be much smaller than the full
lisp compiler.
Of course, not all implementations of the LAP code mechanism will
satisfy all of these goals. The first is the most important.
In particular, many PCL ports will use the portable LAP implementation.
KCL will use the portable implementation in all of its ports. Other
Lisps may have custom LAP implementations for some ports and use the
portable implementation for other ports.
Some Lisps will have a custom LAP implementation but will nonetheless
require the compiler to be loaded to generate LAP closure constructors.
An important point is why we have chosen to take this route rather than
have each implementation implement the method lookup codes itself. This
was done because we are, at PARC, just beginning to study cache behavior
for CLOS programs. As we learn more about this we will want to modify
the caching strategy PCL uses. This architecture, because it leaves
PCL to implement caching behavior makes it possible to do this. Once
this study is complete, implementations may want to do their own, ultra
high performance implementations of caching strategies.
Production of LAP closures is a two step process. In the first step, a
port-specific function is called to take abstract LAP code and produce a
a "lap closure generator". Lap closure generators are functions which
are called with a set of closure variable values and return a LAP
closure.
The intermediary of the lap closure generators provides an important
optimization. Because it is assumed that producing the LAP closure
generator can take much longer than producing a LAP closure from the
generator, PCL attempts to make only one closure generator for each
sequence of LAP code. Because of the way PCL generates the LAP code
sequences, this is quite easy for it to do.
The rest of this document is divided into six parts.
* the metatypes std-instance and fsc-instance
* an abstraction for simple vector indices
* important optimizations
* the port specific function for making lap closure generators
* the actual abstract LAP code
* examples
*** The metatypes STD-INSTANCE and FSC-INSTANCE ***
In PCL, instances with metaclass STANDARD-CLASS are represented using
the metatype STD-INSTANCE. (Note that in Cinco de Mayo PCL, this
metatype is called IWMC-CLASS.) Each port must implement this metatype.
The metatype could be implemented by the following DEFSTRUCT.
(defstruct (std-instance
(:predicate std-instance-p)
(:conc-name %std-instance-)
(:constructor %allocate-std-instance (wrapper slots))
(:constructor %allocate-std-instance-1 ())
(:print-function print-std-instance))
(wrapper nil)
(slots nil))
PCL itself will guarantee correct access to this structure and the
accessors and constructors. With this in mind, the following are
important.
* Being able to type test this structure quickly is critical. See
the :STD-INSTANCE-P opcode.
* The allocation functions should compile inline, do no argument
checking and be as fast as possible.
* The accessor functions should compile inline, do no checking of their
arguments and be as fast as possible. SETF of the accessors should
do the same.
The port is also required to implement the metatype FSC-INSTANCE (called
FUNCALLABLE-INSTANCE, or FIN for short, in Cinco de Mayo PCL). Objects
with this metatype are used, among other things, to implement generic
functions. These objects have field structure associated with them and
are also functions that can be applied to arguments. The fields are the
same as those for STD-INSTANCE, the FSC-INSTANCE metatype has
predicates, print-functions, constructors and accessors as follows:
fsc-instance-p
print-fsc-instance
%fsc-instance-wrapper
%fsc-instance-slots
%allocate-fsc-instance (wrapper slots)
%allocate-fsc-instance-1 ()
In addition, objects of metatype FSC-INSTANCE have a property called the
funcallable instance function. When an FSC-INSTANCE is applied to
arguments, the funcallable instance function is what is actually called.
The funcallable instance function of an FSC-INSTANCE can be changed
using the function SET-FUNCALLABLE-INSTANCE-FUNCTION. There is no
mechanism for obtaining the funcallable instance function of an
FSC-INSTANCE.
It is possible to implement the FSC-INSTANCE metatype in pure Common
Lisp. A simple implementation which uses lexical closures as the
instances and a hash table to record that the lexical closures are of
metatype FSC-INSTANCE is easy to write. Unfortunately, this
implementation adds significant overhead:
to generic-function-invocation (1 function call)
to slot-access (1 function call or one hash table lookup)
to class-of a generic-function (1 hash-table lookup)
In addition, it would prevent the FSC-INSTANCEs from being garbage
collected. In short, the pure Common Lisp implementation really isn't
practical.
Note that previous implementations of FINS were always based on the
lexical closure metatype. In some ports, that provides poor
performance. Those ports may want to consider reimplementing to use the
compiled code metatype. In that implementation strategy, LAP closure
variables would become constants of the compiled code object.
The following note from JonL is of interest when working on a FIN
implementation:
Date: Tue, 16 May 89 05:45:56 PDT
From: Jon L White <jonl@lucid.com>
This isn't a bug in Lucid's compiler -- it's a lurking bug in PCL
that will "bite" most implementations where different settings of
the compiler optimization switches will produce morphologically
different (but of course functionally equivalent) function objects.
The difficulty is in how discriminator codes service cache misses.
They "call out" to (potentially) random functions that will in some
cases "smash" the function object that was actually running as the
discriminator code. This is all right providing you don't return to
that function frame, but alas ...
I know this is a more extensive problem because the code in the
port-independent function 'notice-methods-change' goes out of
its way to do a tail-recursive call to the function that is going
to smash the possibly-executing discriminator code. Here is the
commentary from that code (sic):
;; In order to prevent this we take a simple measure: we just
;; make sure that it doesn't try to reference our its own closure
;; variables after it makes the dcode change. Th